﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Nb.Common.Ioc;

namespace Nb.Common
{
    public interface INbProvider<out T>
    {
        T GetService();
        int Priority { get; }
    }

    public abstract class BaseNbProvider<T> : INbProvider<T>
    {
        public abstract T GetService();
        public virtual int Priority
        {
            get { return ProviderPriority.Default; }
        }

        #region inner class
        public class ProviderPriority
        {
            /// <summary>
            /// 默认100，越大优先级越高
            /// </summary>
            public static int Default
            {
                get
                {
                    return 100;
                }
            }
        }

        #endregion
    }
    
    //todo static to non static !!!
    public class NbServiceManager<T>
    {
        public static NbServiceManager<T> Instance
        {
            get
            {
                var instance = Singleton<NbServiceManager<T>>.Instance;
                if (instance == null)
                {
                    Singleton<NbServiceManager<T>>.Instance = new NbServiceManager<T>();
                }
                return instance;
            }
        }

        private static bool _needSearchAllProviders = true;
        private static IList<Func<INbProvider<T>>> _defaultProviderFuncs = new List<Func<INbProvider<T>>>();

        /// <summary>
        /// 增加默认的ProviderFunc
        /// </summary>
        /// <param name="getProviderFunc"></param>
        public static void AddProviderFunc(Func<INbProvider<T>> getProviderFunc)
        {
            if (getProviderFunc == null)
            {
                throw new ArgumentNullException("getProviderFunc");
            }

            if (_defaultProviderFuncs.Contains(getProviderFunc))
            {
                throw new ArgumentException("不能重复添加getProviderFunc");
            }

            _defaultProviderFuncs.Add(getProviderFunc);
        }
        /// <summary>
        /// 重置初始状态
        /// </summary>
        public static void Reset()
        {
            _needSearchAllProviders = true;
            _defaultProviderFuncs.Clear();
        }

        /// <summary>
        /// 获取所有注册的Provider
        /// </summary>
        /// <returns></returns>
        public static IList<INbProvider<T>> GetProviders()
        {
            var allProviders = new List<INbProvider<T>>();

            var defaultProviders = _defaultProviderFuncs.Select(x => x.Invoke()).OrderByDescending(x => x.Priority).ToList();
            allProviders.AddRange(defaultProviders);

            //log for default providers
            string defaultProviderMessage = string.Format("default providers for {0} count => {1}", typeof(T).Name, defaultProviders.Count);
            Log(defaultProviderMessage);

            if (_needSearchAllProviders)
            {
                var providers = CoreServiceProvider.Current.GetAllInstances<INbProvider<T>>().ToList();
                foreach (var nbProvider in providers)
                {
                    var theOne = allProviders.SingleOrDefault(x => x.GetType() == nbProvider.GetType());
                    if (theOne != null)
                    {
                        //以Ioc注册的nbProvider为准，移除默认
                        allProviders.Remove(theOne);
                    }
                    allProviders.Add(nbProvider);
                }
                //Count > 0，意味着定义了其他的Provider
                //否则，下次没有机会在执行此代码块
                _needSearchAllProviders = providers.Count > 0;

                //log for ioc providers
                Log(string.Format("ioc providers for {0} count => {1}", typeof(T).Name, providers.Count));

                #region 以前的实现

                //var providerTypes = defaultProviders.Select(x => x.GetType()).ToList();
                //var providers = CoreServiceProvider.Current.GetAllInstances<INbProvider<T>>()
                //    .Where(p => providerTypes.All(x => p.GetType() != x))
                //    .ToList();

                ////Count > 0，意味着定义了其他的Provider
                ////否则，下次没有机会在执行此代码块
                //_needSearchAllProviders = providers.Count > 0;
                //allProviders.AddRange(providers);

                ////log for ioc providers
                //Log(string.Format("ioc providers for {0} count => {1}", typeof(T).Name, providers.Count));

                #endregion
            }

            //值越大，越靠前
            var result = allProviders.OrderByDescending(x => x.Priority).ToList();
            return result;
        }

        /// <summary>
        /// 获取优先级最高的Provider提供的服务
        /// </summary>
        /// <returns></returns>
        public static T GetService()
        {
            var allProviders = GetProviders();

            //值越大，越靠前
            var theFirstProvider = allProviders.OrderByDescending(x => x.Priority).First();
            return theFirstProvider.GetService();
        }

        #region log

        //log
        private static bool _logging = true;
        public static void EnableLog(bool logging)
        {
            _logging = logging;
        }
        private static void Log(string message)
        {
            if (_logging)
            {
                UtilsLogger.LogMessage(message);
            }
        }

        #endregion
    }


    public interface INbProviderRegistry<T>
    {
        Func<INbProvider<T>> GetInitDefaultProviderFunc();
        void ClearDefaultProviderFuncs();
        void AddDefaultProviderFunc(Func<INbProvider<T>> getProviderFunc);
        void SetDefaultProviderFuncs(IList<Func<INbProvider<T>>> defaultProviderFuncs);
        IList<INbProvider<T>> GetAllProviders();
        T GetService();
        IList<T> GetServices();
    }

    public abstract class NbProviderRegistry<T, R> : INbProviderRegistry<T> where R : NbProviderRegistry<T, R>, new()
    {
        private static bool _needSearchAllProviders = true;
        private static IList<Func<INbProvider<T>>> _defaultProviderFuncs = new List<Func<INbProvider<T>>>();
        public static R Instance
        {
            get
            {
                if (Singleton<R>.Instance == null)
                {
                    Singleton<R>.Instance = new R();
                }
                return Singleton<R>.Instance;
            }
        }

        protected NbProviderRegistry()
        {

        }

        public abstract Func<INbProvider<T>> GetInitDefaultProviderFunc();

        public void AddDefaultProviderFunc(Func<INbProvider<T>> getProviderFunc)
        {
            if (getProviderFunc == null)
            {
                throw new ArgumentNullException("getProviderFunc");
            }

            _defaultProviderFuncs.Add(getProviderFunc);
            _needSearchAllProviders = true;
        }

        public void SetDefaultProviderFuncs(IList<Func<INbProvider<T>>> defaultProviderFuncs)
        {
            if (defaultProviderFuncs == null)
            {
                _defaultProviderFuncs.Clear();
            }

            _defaultProviderFuncs = defaultProviderFuncs;
            _needSearchAllProviders = true;
        }


        public void ClearDefaultProviderFuncs()
        {
            _defaultProviderFuncs.Clear();
            _needSearchAllProviders = true;
        }

        public IList<INbProvider<T>> GetAllProviders()
        {
            var allProviders = new List<INbProvider<T>>();

            var defaultProviders = _defaultProviderFuncs.Select(x => x.Invoke()).OrderByDescending(x => x.Priority).ToList();
            allProviders.AddRange(defaultProviders);

            //log for default providers
            string defaultProviderMessage = string.Format("default providers for {0} count => {1}", typeof(T).Name, defaultProviders.Count);
            Log(defaultProviderMessage);

            if (_needSearchAllProviders)
            {
                var providers = CoreServiceProvider.Current.GetAllInstances<INbProvider<T>>().ToList();
                foreach (var nbProvider in providers)
                {
                    var theOne = allProviders.SingleOrDefault(x => x.GetType() == nbProvider.GetType());
                    if (theOne != null)
                    {
                        //以Ioc注册的nbProvider为准，移除默认
                        allProviders.Remove(theOne);
                    }
                    allProviders.Add(nbProvider);
                }
                //Count > 0，意味着定义了其他的Provider
                //否则，下次没有机会在执行此代码块
                _needSearchAllProviders = providers.Count > 0;

                //log for ioc providers
                Log(string.Format("ioc providers for {0} count => {1}", typeof(T).Name, providers.Count));
            }

            //值越大，越靠前
            var result = allProviders.OrderByDescending(x => x.Priority).ToList();
            return result;
        }

        /// <summary>
        /// 获取优先级最高的Provider提供的服务
        /// </summary>
        /// <returns></returns>
        public T GetService()
        {
            var allProviders = GetAllProviders();
            //值越大，越靠前
            var theFirstProvider = allProviders.OrderByDescending(x => x.Priority).First();
            return theFirstProvider.GetService();
        }

        public IList<T> GetServices()
        {
            //值越大，越靠前
            var allProviders = GetAllProviders().OrderByDescending(x => x.Priority).ToList();
            var services = allProviders.Select(x => x.GetService()).ToList();
            return services;
        }

        #region log

        //log
        private bool _logging = true;
        public void EnableLog(bool logging)
        {
            _logging = logging;
        }
        private void Log(string message)
        {
            if (_logging)
            {
                UtilsLogger.LogMessage(message);
            }
        }

        #endregion
    }
}
